import {
    Box,
    CircularProgress,
    Grid,
    Link,
    Table,
    TableBody,
    TableCell,
    TableHead,
    TableRow,
    Typography
} from '@mui/material';
import { format } from 'date-fns';
import { useRouter } from 'next/router';
import { useEffect, useState } from 'react';

import Transaction from '../../api/transaction/transaction';
import TransactionManager from '../../api/transaction/transaction-manager';
import MainLayout from '../../components/HOCs/main-layout';
import LoadingWithProgressPopup from '../../components/loading-with-progress-popup';
import { GFSButton } from '../../components/shared/button/gfs-button';
import GFSTable from '../../components/shared/tables/gfs-table';
import TransactionStatus from '../../components/shared/tables/status';
import { ErrorStatus } from '../../constants/error-status';
import { getStatusName } from '../../constants/status';
import { useInfiniteScroll } from '../../hooks/infinitive-scroll';
import { useLoadTransactions } from '../../hooks/transaction-load-more-';
import NumberTool from '../../libs/number-tool';
import { getBSCScanUrl, getTokenIcon } from '../../libs/utilities';

const TransactionPage = () => {
    const router = useRouter();
    const [disbursementID, setDisbursementID] = useState(null);
    const [downloading, setDownloading] = useState(false);
    const [downloadProgress, setDownloadProgress] = useState<number>(0);
    const [, setDownloadError] = useState<{ code: string; message: string }>(undefined);

    const { loading, disbursement, items, hasNextPage, error, loadMore } =
        useLoadTransactions(disbursementID);

    const [pageLoading, setPageLoading] = useState(true);

    const [sentryRef] = useInfiniteScroll({
        loading,
        hasNextPage,
        onLoadMore: loadMore,
        disabled: !!error,
        rootMargin: '0px 0px 400px 0px'
    });

    useEffect(() => {
        if (!router.isReady) return;
        const { id } = router.query;
        setDisbursementID(id);
    }, [router.isReady]);

    useEffect(() => {
        const load = async () => {
            await loadMore();
            setPageLoading(false);
        };

        if (disbursementID) {
            load().then();
        }
    }, [disbursementID]);

    const downloadCSV = async () => {
        setDownloadProgress(0);
        setDownloading(true);
        try {
            let page = 0;
            let loading = true;
            const transactions: Transaction[] = [];

            while (loading) {
                const { list, hasMore } = await TransactionManager.getByPage(disbursementID, page);
                transactions.push(...list);
                setDownloadProgress(transactions.length);
                loading = hasMore;
                page++;
            }

            let content = 'data:text/csv;charset=utf-8,';
            content += 'id,name,amount,fee,wallet_address,email,status';

            if (disbursement.currency != 'SLP') {
                content += ',transaction_hash';
            }

            content += '\r\n';

            transactions.forEach((transaction) => {
                const array = [
                    'GFS' + transaction.id?.toString(),
                    transaction.name,
                    transaction.amount + ' ' + disbursement?.currency,
                    transaction.gasFee?.amount + ' ' + disbursement?.currency,
                    transaction.walletAddress,
                    transaction.email,
                    getStatusName(transaction.status)
                ];

                if (disbursement.currency != 'SLP') {
                    array.push(transaction.transactionHash);
                }

                const row = array.join(',');
                content += row + '\r\n';
            });

            const encodedUri = encodeURI(content);
            const link = document.createElement('a');
            link.setAttribute('href', encodedUri);
            link.setAttribute('download', 'GFS Disbursement.csv');
            document.body.appendChild(link);
            link.click();
            setDownloading(false);
        } catch (e) {
            setDownloadError(e);
            console.log('error', e);
            setTimeout(() => {
                setDownloading(false);
                setDownloadError(undefined);
            }, 5000);
        }
    };

    const generateReport = (
        numberOfTransactions: number,
        totalAmount: number = null
    ): string | JSX.Element => {
        if (!numberOfTransactions) {
            return 'None';
        }

        let message: string | JSX.Element =
            (numberOfTransactions ? numberOfTransactions : 0) +
            ' ' +
            (numberOfTransactions == 1 ? 'transaction' : 'transactions');

        if (totalAmount) {
            message = (
                <>
                    {message} (
                    <Box
                        component="img"
                        sx={{
                            height: 15,
                            width: 15,
                            marginRight: '0.2rem',
                            marginTop: '-0.2rem'
                        }}
                        alt="Icon"
                        src={getTokenIcon(disbursement.currency)}
                    />
                    {totalAmount ? NumberTool.format(totalAmount) : 0} {disbursement.currency})
                </>
            );
        }

        return message;
    };

    const getErrorMessage = (error: { code: number; message: string }) => {
        if (error.code === ErrorStatus.YOURE_NOT_ALLOWED_TO_ACCESS_THIS) {
            return "This disbursement doesn't exist.";
        } else {
            return error.message;
        }
    };

    return (
        <MainLayout>
            <Box sx={{ pl: 6, pr: 6, pt: 6 }}>
                <Typography variant="h2" color="white" sx={{ pb: 3 }}>
                    Transactions
                </Typography>

                {pageLoading ? (
                    <Typography variant="h6" color="white">
                        Loading...
                    </Typography>
                ) : (
                    <Box sx={{ pb: 4 }}>
                        <Grid
                            sx={{ pt: 2, pb: 2 }}
                            container
                            justifyContent="space-between"
                            spacing={2}
                        >
                            <Grid item xs={8}>
                                {disbursement && (
                                    <>
                                        <Typography variant="h4" color="white">
                                            {disbursement ? disbursement.title : ''}
                                        </Typography>

                                        <Typography
                                            variant="body2"
                                            color="white"
                                            sx={{ pt: 2, pb: 4 }}
                                        >
                                            <b>Total</b>: {generateReport(disbursement.total)}
                                            <br />
                                            <b>Uploaded</b>:{' '}
                                            {generateReport(
                                                disbursement.saved,
                                                disbursement.totalAmount
                                            )}
                                            <br />
                                            <b>Successful</b>:{' '}
                                            {generateReport(
                                                disbursement.sent,
                                                disbursement.sentAmount
                                            )}
                                            <br />
                                            <b>Failed</b>:{' '}
                                            {generateReport(
                                                disbursement.failed,
                                                disbursement.failedAmount
                                            )}
                                        </Typography>
                                    </>
                                )}
                            </Grid>
                            <Grid item xs={4} textAlign="right">
                                {items && items.length > 0 && (
                                    <GFSButton
                                        variant="contained"
                                        component="label"
                                        onClick={downloadCSV}
                                        sx={{
                                            background: '#5148fc',
                                            '&:hover': {
                                                background: '#5148fc',
                                                color: '#ffffff'
                                            }
                                        }}
                                    >
                                        Download CSV
                                    </GFSButton>
                                )}
                            </Grid>
                        </Grid>

                        {!error ? (
                            <Box>
                                {items && items.length && (
                                    <GFSTable>
                                        <Table sx={{ minWidth: 650 }} aria-label="simple table">
                                            <TableHead>
                                                <TableRow>
                                                    <TableCell>Reference #</TableCell>
                                                    <TableCell>Timestamp</TableCell>
                                                    <TableCell>Recipient</TableCell>
                                                    <TableCell align="center">Amount</TableCell>
                                                    <TableCell align="center">Fee</TableCell>
                                                    {disbursement.currency.includes('BSC') && (
                                                        <TableCell align="center">
                                                            Transaction Hash
                                                        </TableCell>
                                                    )}
                                                    <TableCell align="center">Status</TableCell>
                                                </TableRow>
                                            </TableHead>
                                            <TableBody>
                                                {items?.length > 0 &&
                                                    items.map((row) => (
                                                        <TableRow
                                                            key={row.id}
                                                            sx={{
                                                                '&:last-child td, &:last-child th':
                                                                    {
                                                                        border: 0
                                                                    }
                                                            }}
                                                            hover={true}
                                                        >
                                                            <TableCell>GFS{row.id}</TableCell>
                                                            <TableCell>
                                                                {format(
                                                                    row.timestamp,
                                                                    'MM / dd / yyyy'
                                                                )}
                                                                {' - '}
                                                                {format(row.timestamp, 'hh:mma')}
                                                            </TableCell>
                                                            <TableCell>
                                                                {row.name && (
                                                                    <>
                                                                        <span>{row.name}</span>
                                                                        <br />
                                                                    </>
                                                                )}
                                                                {row.walletAddress && (
                                                                    <>
                                                                        <span>
                                                                            {row.walletAddress}
                                                                        </span>
                                                                        <br />
                                                                    </>
                                                                )}
                                                                {row.email && (
                                                                    <>
                                                                        <span>{row.email}</span>
                                                                        <br />
                                                                    </>
                                                                )}
                                                            </TableCell>
                                                            <TableCell align="center">
                                                                {row.amount ? (
                                                                    <>
                                                                        <Box
                                                                            component="img"
                                                                            sx={{
                                                                                height: 15,
                                                                                width: 15,
                                                                                marginRight:
                                                                                    '0.2rem',
                                                                                marginTop: '-0.2rem'
                                                                            }}
                                                                            alt="Icon"
                                                                            src={getTokenIcon(
                                                                                disbursement.currency
                                                                            )}
                                                                        />
                                                                        {NumberTool.format(
                                                                            row.amount,
                                                                            disbursement.currency
                                                                        )}{' '}
                                                                        {disbursement.currency}
                                                                    </>
                                                                ) : (
                                                                    '-'
                                                                )}
                                                            </TableCell>
                                                            <TableCell align="center">
                                                                {row.gasFee?.amount ? (
                                                                    <>
                                                                        <Box
                                                                            component="img"
                                                                            sx={{
                                                                                height: 15,
                                                                                width: 15,
                                                                                marginRight:
                                                                                    '0.2rem',
                                                                                marginTop: '-0.2rem'
                                                                            }}
                                                                            alt="Icon"
                                                                            src={getTokenIcon(
                                                                                disbursement.currency
                                                                            )}
                                                                        />
                                                                        {NumberTool.format(
                                                                            row.gasFee?.amount,
                                                                            disbursement.currency
                                                                        )}{' '}
                                                                        {disbursement.currency}
                                                                    </>
                                                                ) : (
                                                                    '-'
                                                                )}
                                                            </TableCell>
                                                            {disbursement.currency.includes(
                                                                'BSC'
                                                            ) && (
                                                                <TableCell align="center">
                                                                    {row.transactionHash ? (
                                                                        <Link
                                                                            href={getBSCScanUrl(
                                                                                row.transactionHash
                                                                            )}
                                                                            target="_blank"
                                                                        >
                                                                            View on BSC Scan
                                                                        </Link>
                                                                    ) : (
                                                                        '-'
                                                                    )}
                                                                </TableCell>
                                                            )}
                                                            <TableCell align="center">
                                                                {row.status ? (
                                                                    <TransactionStatus
                                                                        status={row.status}
                                                                    />
                                                                ) : (
                                                                    '-'
                                                                )}
                                                                {row.errorMessage && (
                                                                    <Typography
                                                                        align={'center'}
                                                                        variant={'subtitle2'}
                                                                        sx={{
                                                                            color: 'var(--color-negative)',
                                                                            maxWidth: 200,
                                                                            margin: 'auto',
                                                                            wordBreak: 'break-word'
                                                                        }}
                                                                    >
                                                                        {row.errorMessage}
                                                                    </Typography>
                                                                )}
                                                            </TableCell>
                                                        </TableRow>
                                                    ))}
                                            </TableBody>
                                        </Table>
                                    </GFSTable>
                                )}

                                {!loading && (!items || !items.length) && (
                                    <Typography className="top-20">
                                        No transactions yet...
                                    </Typography>
                                )}

                                {(loading || hasNextPage) && (
                                    <Box
                                        display="flex"
                                        justifyContent="center"
                                        alignItems="center"
                                        sx={{ pt: 4 }}
                                    >
                                        <CircularProgress
                                            ref={sentryRef}
                                            sx={{ color: '#ffffff' }}
                                        />
                                    </Box>
                                )}
                            </Box>
                        ) : (
                            <Typography className="top-20" sx={{ color: 'var(--color-negative)' }}>
                                {error && error.message
                                    ? getErrorMessage(error)
                                    : 'No transactions yet...'}
                            </Typography>
                        )}
                    </Box>
                )}
            </Box>

            {downloading && disbursement && (
                <LoadingWithProgressPopup
                    show={downloading}
                    message={'Downloading CSV...'}
                    progress={downloadProgress}
                    total={disbursement.total}
                />
            )}
        </MainLayout>
    );
};

export default TransactionPage;
